import gst
import pygst
import time
import traceback
import gobject

class Player:
  def __init__(self):
    print "Player constructor called. Running _initialize"
    self._initialize()
    self._SetVolume(100)

  def _initialize(self):
    try:
      print "PLAYER INITIALIZING"
      self._speed = 1
      self._timer = None
      self.player = gst.parse_launch(
          "gnomevfssrc name=source ! id3lib name=id3 ! dspmp3sink name=sink")
      self.source = self.player.get_by_name("source")
      self.sink = self.player.get_by_name("sink")
      self.player.set_name("player")
      self.playing = False
      bus = self.player.get_bus()
      bus.add_signal_watch()
      bus.connect('message', self.on_message)
      time.sleep(0.10)
    except gobject.GError:
      # We're probably in the simulator if we get here.
      print "Caught exception (probably in the simulator):"
      traceback.print_exc()
      self.player = None
      self.source = None
      self.sink = None
      self.playing = False
      print "...continuing unabated."
      return


  def on_message(self, bus, message):
    print "---- player message:", message, "of type", message.type
    t = message.type
    if t == gst.MESSAGE_EOS:
       self.player.set_state(gst.STATE_NULL)
       self.playing = False
       self._Finished()
    elif t == gst.MESSAGE_ERROR:
       self.player.set_state(gst.STATE_NULL)
       self.playing = False
       self._Finished()

  def play(self, filename, on_finish=None):
    if self.playing:
      print "-------- Already playing. Stopping."
      self.stop()
      self._initialize()
    print "------------- start playing", filename
    self.playing = True
    self._SetLocation(filename)
    self._SetPlayerState(gst.STATE_PLAYING)
    self.paused = False
    self.on_finish = on_finish

  def stop(self):
    self._SetPlayerState(gst.STATE_NULL)

  def pause(self):
    if self.playing:
      if self.paused:
        self._SetPlayerState(gst.STATE_PLAYING)
        self.paused = False
      else:
        self._SetPlayerState(gst.STATE_PAUSED)
        self.paused = True

  def set_speed(self, speed, accel=0):
    self._speed = speed
    self._accel = accel

    # Run the timer callback once to ff/rwd immediately.
    # If OnTimer returns false then there's no need to start the
    # timeout.
    if not self._timer and self.OnTimer():
      self._timer = gobject.timeout_add(750, self.OnTimer)

  def position(self):
    pos = self.player.query_position(gst.FORMAT_TIME, None)[0]
    return int(pos / 1000000000)

  def length(self):
    dur = self.player.query_duration(gst.FORMAT_TIME, None)[0]
    return int(dur / 1000000000)

  def OnTimer(self):
    print "FF/RWD timer running with speed", self._speed
    if self._speed == 1:
      print "Killing ff/rwd timer because speed is 1."
      self._timer = None
      return False
    try:
      pos = self.player.query_position(gst.FORMAT_TIME, None)[0]
      len = self.player.query_duration(gst.FORMAT_TIME, None)[0]
      event = gst.event_new_seek(1, gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH,
          gst.SEEK_TYPE_CUR,
          min(len - 1, max(0, pos + self._speed * 1000000000)),
          gst.SEEK_TYPE_NONE, 0)
      if not self.player.send_event(event):
        print "Failed to set speed of playback to", speed
      self._speed += self._accel
    finally:
      return True

  def _SetPlayerState(self, state):
    if self.player is not None:
      self.player.set_state(state)

  def _SetLocation(self, filename):
    if self.source is not None:
      self.source.set_property("location", filename)

  def _SetVolume(self, volume):
    if self.sink is not None:
      self.sink.set_property('volume',  volume * 65535 / 100)

  def _Finished(self):
    print "Stream finished. Calling Player._initialize()."
    self._initialize()
    if self.on_finish:
      on_finish = self.on_finish
      self.on_finish = None
      on_finish()
